import json
import logging
import time
import urllib.parse

import requests

import coin.exchange.base.kr_rest.rest_client_base as rcb
from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin.exchange.util.rate_limit import RateLimiter

HITBTC_API_URL = 'https://api.hitbtc.com/api/2/'


class HitbtcSyncQueryer(object):
  def __init__(self, key_file, timeout=10):
    self._timeout = timeout
    self._rate_limit = RateLimiter(10, 1)
    self._key = AuthKey.from_file(key_file=key_file)
    self._auth = (self._key.access_key, self._key.secret_key)
    self._logger = logging.getLogger(__name__)

  def auth_request(self, http_method, path, params):
    url = urllib.parse.urljoin(HITBTC_API_URL, path)
    try:
      if http_method == 'GET':
        response = requests.get(url, params=params, auth=self._auth, timeout=self._timeout)
      elif http_method == 'POST':
        response = requests.post(url, json=params, auth=self._auth, timeout=self._timeout)
      elif http_method == 'PUT':
        response = requests.put(url, json=params, auth=self._auth, timeout=self._timeout)
      else:
        raise ValueError('Invalid http method %s' % http_method)
      return response
    except requests.exceptions.RequestException as e:
      self._logger.exception('RequestException: %s', e)
      raise
    except json.JSONDecodeError as e:
      self._logger.exception('JsonDecodeException: %s\n %s', response.content, e)
      raise
    except Exception as e:
      self._logger.exception('Unknown exception, %s', e)
      raise

  def query_nocheck(self, http_method, endpoint, params=None):
    req_timestamp = time.time()
    response = self.auth_request(http_method, endpoint, params)
    res_timestamp = time.time()
    if response.status_code == 200:
      update = rcb.RestUpdate(req_timestamp,
                              res_timestamp,
                              response.json(),
                              status=response.status_code)
    else:
      update = rcb.RestUpdate(req_timestamp,
                              res_timestamp,
                              response.text,
                              status=response.status_code)
    return update

  def query(self, http_method, path, params=None, disable_rate_limit=False):
    assert http_method in ('GET', 'POST', 'PUT'), http_method
    if not disable_rate_limit:
      while not self._rate_limit.check():
        time.sleep(0.1)
    else:
      self._rate_limit.check()
    return self.query_nocheck(http_method, path, params=params)


class HitbtcNativePrivateClient(object):
  def __init__(self, *, key_file, timeout=10):
    self._queryer = HitbtcSyncQueryer(key_file, timeout=timeout)

  def _query(self, http_method, path, params=None):
    return self._queryer.query(http_method, path, params=params)

  def _query_get_account_balance(self):
    method = 'GET'
    path = 'account/balance'
    update = self._query(method, path)
    return update
